package com.nsxy.common.utils;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.domain.Specifications;

/**
 * jpa查询条件
 * @author 潜行的青衣
 * @see
 */
public class Criteria<T> {

	private List<Boolean> units = new ArrayList<Boolean>();
	
	private List<Specification<T>> specifications = new ArrayList<Specification<T>>();
	
	public Criteria<T> and() {
		units.add(true);
		return this;
	}
	
	public Criteria<T> or() {
		units.add(false);
		return this;
	}
	
	public Criteria<T> eq(final String field, final Object value) {
		Specification<T> spec = SpecificationUtils.eq(field, value); 
		specifications.add(spec);
		return this;
	}
	
	public Criteria<T> gt(final String field, final Number value) {
		Specification<T> spec = SpecificationUtils.gt(field, value); 
		specifications.add(spec);
		return this;
	}
	
	public <Y extends Comparable<? super Y>> Criteria<T> greaterThan(final String field, final Y value) {
		Specification<T> spec = SpecificationUtils.greaterThan(field, value); 
		specifications.add(spec);
		return this;
	}
	
	public <Y extends Comparable<? super Y>> Criteria<T> greaterThanOrEqualTo(final String field, final Y value) {
		Specification<T> spec = SpecificationUtils.greaterThanOrEqualTo(field, value); 
		specifications.add(spec);
		return this;
	}
	
	public Criteria<T> ge(final String field, final Number value) {
		Specification<T> spec = SpecificationUtils.ge(field, value); 
		specifications.add(spec);
		return this;
	}
	
	public Criteria<T> lt(final String field, final Number value) {
		Specification<T> spec = SpecificationUtils.lt(field, value); 
		specifications.add(spec);
		return this;
	}
	
	public Criteria<T> le(final String field, final Number value) {
		Specification<T> spec = SpecificationUtils.le(field, value); 
		specifications.add(spec);
		return this;
	}
	
	public <Y extends Comparable<? super Y>> Criteria<T> lessThan(final String field, final Y value) {
		Specification<T> spec = SpecificationUtils.lessThan(field, value); 
		specifications.add(spec);
		return this;
	}
	
	public <Y extends Comparable<? super Y>> Criteria<T> lessThanOrEqualTo(final String field, final Y value) {
		Specification<T> spec = SpecificationUtils.lessThanOrEqualTo(field, value); 
		specifications.add(spec);
		return this;
	}
	
	public <Y extends Comparable<? super Y>> Criteria<T> between(final String field, final Y value1, final Y value2) {
		Specification<T> spec = SpecificationUtils.between(field, value1, value2); 
		specifications.add(spec);
		return this;
	}
	
	public Criteria<T> like(final String field, final String value) {
		Specification<T> spec = SpecificationUtils.like(field, value); 
		specifications.add(spec);
		return this;
	}
	
	public Specifications<T> toSpecifications() {
		Specifications<T> spec = null;
		if(this.units.size() <= this.specifications.size()) {
			Iterator<Boolean> uit = this.units.iterator();
			Iterator<Specification<T>> sit = this.specifications.iterator();
			int index = 0;
			boolean unit = false;
			Specification<T> elem = null;
			while(uit.hasNext()) {
				unit = uit.next();
				elem = sit.next();
				if(index > 0) {
					if(unit) {
						spec = spec.and(elem);
					} else {
						spec = spec.or(elem);
					}
				} else {
					spec = Specifications.where(elem);
				}
				index ++;
			}
		}
		return spec;
	}
}
